package c2.cross.business.rank.h;

import c2.cross.business.rank.CrossRankDao;
import c2.cross.business.rank.data.CrossRankData;
import cate.game.rank.po.Rank;
import cate.game.role.RoleSnapshot;
import easy.java.dev.note.NoteField;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.annotation.Transient;

import java.util.*;

/**
 * 跨服排行实现
 */
@Slf4j
public abstract class BaseSingleValueRankHandler implements ICrossRankHandler{
    /**
     * 保存数据库的最小间隔时间
     */
    private static final long SAVE_INTERVAL = 60000;
    @Getter
    private final int rankId;
    @NoteField("榜单")
    private CrossRankData rankData;
    @NoteField("上次存储检测时间")
    private long lastSaveCheckTime;
    @Transient
    private final CrossRankDao dao;

    public BaseSingleValueRankHandler(int rankId, CrossRankDao dao) {
        this.rankId = rankId;
        this.dao = dao;
        rankData = this.dao.getByKey(getTag(), CrossRankData.class);
        if (rankData == null) {
            rankData = createSaveData();
        }
    }

    protected abstract String getTag();

    /**
     * 上榜数量限制
     */
    protected abstract int getRankNum();

    protected CrossRankData createSaveData() {
        CrossRankData spo = new CrossRankData();
        spo.setTag(getTag());
        return spo;
    }

    /**
     * 尝试获取排行列表
     */
    protected List<Rank> tryGetRankList() {
        if (rankData.getList() == null) {
            rankData.setList(new ArrayList<>());
        }
        return rankData.getList();
    }

    /**
     * 查询对应角色Uid的排行数据
     *
     * @param roleUid 角色Uid
     */
    @Override
    public Rank findRankByRoleUid(String roleUid) {
        try {
            for (Rank rank : tryGetRankList()) {
                if (StringUtils.equals(roleUid, rank.owner.uid)) {
                    return rank;
                }
            }
            return null;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 根据唯一ID获取对应的排名
     *
     * @return -1表示没有进入排名
     */
    @Override
    public int getRankIndex(String uid) {
        try {
            List<Rank> list = tryGetRankList();
            for (int i = 0; i < list.size(); i++) {
                Rank rank = list.get(i);
                if (StringUtils.equals(rank.owner.uid, uid)) {
                    return i + 1;
                }
            }
            return -1;
        } catch (Exception e) {
            return -1;
        }
    }

    /**
     * 获取排行列表
     *
     * @param limit 限制数量
     */
    @Override
    public List<Rank> getRankList(int limit) {
        try {
            List<Rank> list = tryGetRankList();
            if (limit == 0 || list.size() <= limit) {
                return new ArrayList<>(list);
            }
            return new ArrayList<>(list.subList(0, limit));
        } catch (Exception e) {
            // nothing
        }
        return Collections.emptyList();
    }

    /**
     * 记录数值
     *
     * @param snapshot 角色快照
     * @param newValue 新记录值
     */
    public synchronized void record(RoleSnapshot snapshot, long newValue) {
        if (snapshot == null) {
            return;
        }
        List<Rank> list = tryGetRankList();
        // 是否已经上榜
        Rank his = findRankByRoleUid(snapshot.uid);
        if (his != null) {
            his.owner = snapshot.copy();
        }
        if (list.size() >= getRankNum()) {
            Rank last = list.get(list.size() - 1);
            if (last.value > newValue) {
                // 没有进排行榜
                return;
            }
        }
        if (his != null) {
            his.value = newValue;
        } else {
            Rank rank = new Rank(snapshot, newValue);
            if (list.size() >= getRankNum()) {
                list.remove(list.size() - 1);
            }
            list.add(rank);
        }
        sort();
    }

    /**
     * 执行排序
     */
    public synchronized void sort() {
        tryGetRankList().sort(Comparator.comparing(Rank::getValue)
                .reversed()
                .thenComparing(Rank::getRecordTime));
    }

    /**
     * 数据清空
     */
    public synchronized void clear() {
        tryGetRankList().clear();
    }

    /**
     * 移除指定服务器ID的数据
     *
     * @param srvId 服务器ID
     */
    public synchronized void removeBySrvId(int srvId) {
        tryGetRankList().removeIf(rank -> rank.owner.base.srvId == srvId);
    }

    public void changeSrvId(int oldId, int curId) {
        tryGetRankList().forEach(rank -> {
            if (rank.owner != null && rank.owner.base != null && rank.owner.base.srvId == oldId) {
                rank.owner.base.srvId = curId;
            }
        });
    }

    /**
     * 循环
     */
    public void tick() {
        long nowTime = System.currentTimeMillis();
        if (nowTime - lastSaveCheckTime >= SAVE_INTERVAL) {
            lastSaveCheckTime = nowTime;
            save();
        }
    }

    public void save() {
        try {
            dao.save(rankData);
        }catch (Exception e) {
            log.error("排行榜{}保存失败", rankData.getTag());
        }
    }
}
